#INDIVIDUAL MODELS
import random
import math

from django.db import models
#from game.combat.models import damageModifierCollection
from game.attributes.models import trait
from game.actions.models import action
from game.common.logger import logger


GENDER_CHOICES=(
	('M', 'Male'),
	('F', 'Female'),
	('N', 'None'),
)


class monsterType(models.Model):
	"""
	The base type for a monster. Think Genus of Genus species
	Defines which hit/mag die to use.
	"""
	name = models.CharField(max_length = 20, unique = True)
	hitDie = models.IntegerField(default = 8)
	magicDie = models.IntegerField(default = 6)
		
	def __unicode__(self):
		return self.name

class species(models.Model):
	"""
	A basic monster, used as a model that creates individuals
	Think species of Genus species
	"""
	name = models.CharField(max_length = 30, unique = True) #name of the species
	description = models.CharField(max_length = 200)
	size = models.ForeignKey('attributes.size')
	type = models.ForeignKey('monsterType')
	image = models.CharField(max_length = 50, default="monster.gif")
	str  = models.IntegerField(default = 1)
	dex  = models.IntegerField(default = 1)
	con  = models.IntegerField(default = 1)
	int  = models.IntegerField(default = 1)
	speed = models.IntegerField(default = 1)
	toHit = models.IntegerField(default = 0)
	defence = models.IntegerField(default = 0)
	HD = models.IntegerField(default = 1)
	MD = models.IntegerField(default = 1)
	
	dmc = models.ForeignKey('damage.damageModifierCollection', blank = True, null = True)
	
	traits =  models.ManyToManyField(trait)
	actions = models.ManyToManyField(action)
	
	class Meta():
		abstract = False
		
	def __unicode__(self):
		return self.name
	
	def hasTrait(self, trait):
		if self.traits.filter(id = trait.id).count() > 0:
			return True
		return False

class individual(models.Model):
	"""An individual instance of an a species"""
	user = models.ForeignKey('auth.user', blank = True, null = True) #user who owns the individual
	group = models.ForeignKey('group', blank = True, null = True)
	
	firstName = models.CharField(max_length = 30)
	lastName = models.CharField(max_length = 30)
	gender = models.CharField(max_length = 1, choices = GENDER_CHOICES)
	species = models.ForeignKey('species')
	
	#stat offsets get combined with species stats for total stat
	strOffset = models.IntegerField(default = 0)
	dexOffset = models.IntegerField(default = 0)
	conOffset = models.IntegerField(default = 0)
	intOffset = models.IntegerField(default = 0)
	speedOffset = models.IntegerField(default = 0)
	
	toHitOffset = models.IntegerField(default = 0)
	defenceOffset = models.IntegerField(default = 0)
	
	HDOffset = models.IntegerField(default = 0)
	MDOffset = models.IntegerField(default = 0)
	
	totalHP = models.IntegerField(default = 1)
	totalMP = models.IntegerField(default = 1)
	
	damage = models.IntegerField(default = 0) #damage taken
	cast = models.IntegerField(default = 0)   #MP cast
	
	skillPointsTotal = models.IntegerField(default = 0)
	skillPointsSpent = models.IntegerField(default = 0)
	
	traits_aquired= models.ManyToManyField(trait, blank=True)
	actions_aquired=models.ManyToManyField(action, blank=True)
	
	dmc = models.ForeignKey('damage.damageModifierCollection', blank = True, null = True)
	
	def __unicode__(self):
		return self.name
		
	@property
	def name(self):
		return self.firstName+' '+self.lastName
	
	@property	
	def hpLeft(self):
		return self.totalHP-self.damage
		
	@property
	def mpLeft(self):
		return self.totalMP - self.cast
		
	@property
	def skillPoints(self):
		return self.skillPointsTotal - self.skillPointsSpent
		
	@property
	def baseStr(self):
		return self.strOffset + self.species.str
	@property
	def baseDex(self):
		return self.dexOffset + self.species.dex	
	@property
	def baseCon(self):
		return self.conOffset + self.species.con
	@property
	def baseInt(self):
		return self.intOffset + self.species.int
	@property
	def baseSpeed(self):
		return self.speedOffset + self.species.speed
	@property
	def size(self):
		return self.species.size
	@property
	def HDTotal(self):
		return self.HDOffset + self.species.HD
	@property
	def MDTotal(self):
		return self.MDOffset + self.species.MD
	
	def addHD(self):
		#Adds a HD to the individual and increases totalHP
		try:
			self.HDOffset+=1
			newHP = random.randint(1, self.species.type.hitDie)
			self.totalHP += newHP
			self.save()
			return 1
		except:
			return 0
			
	def addMD(self):
		#Adds a MD to the individual and increases totalMP
		try:
			self.MDOffset+=1
			newMP = random.randint(1, self.species.type.magicDie)
			self.totalMP += newMP
			self.save()
			return 1
		except:
			return 0
	
	def getDefence(self, dType):
		#*Checks individuals effects and equipment for defence against
		#dtype
		totalDefence = 0
		
		#Dont call if DMC doesn't exist
		if self.species.dmc is not None:
			totalDefence += self.species.dmc.getDefence(dType)
		if self.dmc is not None:
			totalDefence += self.dmc.getDefence(dType)
			
		return totalDefence
		
	def addDamage(self, dam):
		#adds the amount of damage to the individual
		try:
			self.damage += dam
			if self.damage > self.totalHP:
				self.damage=self.totalHP
			self.save()
			#return total damage dealt
			return dam
		except:
			return 0
			
	def expendMP(self, mp):
		#adds to the total mp used
		try:
			self.cast += mp
			if self.cast > self.totalMP:
				self.cast=self.totalMP
			self.save()
			return 1
		except:
			return 0
				
	def hasTrait(self, trait):
		return trait in self.traits()
		#if self.species.hasTrait(trait) \
		#or self.traits_aquired.filter(id=trait.id).count() > 0:
		#	return True
		#return False
	def hasAction(self, action):
		return action in self.getAllActions()	
	
	@property
	def traits(self):
		return list(self.traits_aquired.all()) + list(self.species.traits.all())
	
	def getAllActions(self):
		return list(self.actions_aquired.all()) + list(self.species.actions.all())
	
	def getStatBonus(self, stat):
		if stat == 'str':
			func = self.baseStr
		elif stat == 'dex':
			func = self.baseDex
		elif stat == 'con':
			func = self.baseCon
		elif stat == 'int':
			func = self.baseInt
		return math.floor((func()-10)/2)
	
	def isAlive(self):
		if self.hpLeft > 0:
			logger.debug("%s is still alive"%(self.name))
			return True
		else:
			logger.debug("%s is dead"%(self.name))
			return False
	
	
class group(models.Model):
	class Meta():
		abstract = False
		
	def allMonsters(self):
		return individual.objects.filter(group=self)
